#ifndef THREAD_POOL_IMPL_H_
#define THREAD_POOL_IMPL_H_

#include "BaseThreadPool.hpp"

#include <boost/asio/io_service.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
#include <boost/asio/strand.hpp>

#include <iostream>
#include <functional>

#include <mutex>

namespace threadPool{
    template<typename Return=void>
class ThreadPoolImpl:
public BaseThreadPool<Return>{
    public:
        using AsioServer = boost::asio::io_service;
        using task = std::function<void()>;
        using ThreadPoolWorkMode = BaseThreadPoolOp::ThreadPoolWorkMode;
        

        void run() override{
            std::cout << "run" << std::endl;
            for(int i = 0;i<m_thread_num_;i++){
                m_worker_threads_.create_thread(boost::bind(&ThreadPoolImpl::workThread,this));
            }
        }

        void stop() override{
            m_worker_threads_.join_all();
        }

        void addtask(task && t){
            // std::cout << "addtask" << std::endl;

            switch (m_mode_)
            {
                case ThreadPoolWorkMode::Dispatcher :
                    m_server_.dispatch(t);
                    break;

                case ThreadPoolWorkMode::Post :
                    m_server_.post(t);
                    break;
                
                default:
                    break;
            }
            
        }

        void workThread(){
            m_server_.run();
        }

        void setTreadPool(const uint8_t threadNum)override{
            m_thread_num_ = threadNum;
        }

        void setThreadPoolMode(ThreadPoolWorkMode  mode) override{
            m_mode_ = mode;
        }

        static BaseThreadPool<Return> * getInstance(){
            
            static std::once_flag oc;
            std::call_once(oc,[](){
                if(BaseThreadPoolOp::Instance_ == nullptr)
                 BaseThreadPoolOp::Instance_ = new ThreadPoolImpl();
            });

            return dynamic_cast<BaseThreadPool<Return> *>(BaseThreadPoolOp::Instance_);
        }
    private:
        

        ThreadPoolImpl():
        m_work_(m_server_)
        {
            
        }

        ~ThreadPoolImpl(){
            m_worker_threads_.join_all();
        }

    private:
        AsioServer m_server_;
        boost::asio::io_service::work m_work_;
        boost::thread_group m_worker_threads_;
        ThreadPoolWorkMode m_mode_;
        uint8_t m_thread_num_;
        
};

}

#endif